package com.polidea.rxandroidble.sample.example4_characteristic;

import android.bluetooth.BluetoothGattCharacteristic;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;

import com.polidea.rxandroidble.RxBleConnection;
import com.polidea.rxandroidble.RxBleDevice;
import com.polidea.rxandroidble.sample.DeviceActivity;
import com.polidea.rxandroidble.sample.R;
import com.polidea.rxandroidble.sample.SampleApplication;
import com.encode.DataTools;
import com.polidea.rxandroidble.sample.util.HexString;
import com.polidea.rxandroidble.utils.ConnectionSharingAdapter;
import com.trello.rxlifecycle.components.support.RxAppCompatActivity;

import java.util.UUID;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subjects.PublishSubject;

import static com.trello.rxlifecycle.android.ActivityEvent.PAUSE;

public class MultCharActivity extends RxAppCompatActivity {

    public static final String EXTRA_CHARACTERISTIC_UUID = "extra_uuid";
    @BindView(R.id.connect)
    Button connectButton;
    @BindView(R.id.read_output)
    TextView readOutputView;
    @BindView(R.id.read_hex_output)
    TextView readHexOutputView;
    @BindView(R.id.write_input)
    TextView writeInput;
    @BindView(R.id.read)
    Button readButton;
    @BindView(R.id.write)
    Button writeButton;
    @BindView(R.id.notify)
    Button notifyButton;
    @BindView(R.id.spinner)
    Button spinner;

    private UUID uuidNotify = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e");
    // send UUID
    private UUID uuidSend = UUID.fromString("6e400002-b5a3-f393-e0a9-e50e24dcca9e");
    //name
    private UUID uuidwrName = UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
    // sed 1 sed 2
    private UUID r1 = UUID.fromString("00002a01-0000-1000-8000-00805f9b34fb");
    //不知道啥。
    private UUID r2 = UUID.fromString("00002a04-0000-1000-8000-00805f9b34fb");


    private PublishSubject<Void> disconnectTriggerSubject = PublishSubject.create();
    private Observable<RxBleConnection> connectionObservable;
    private RxBleDevice bleDevice;
    private byte[][] opearteData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mult_character);
        ButterKnife.bind(this);
        String macAddress = getIntent().getStringExtra(DeviceActivity.EXTRA_MAC_ADDRESS);

        bleDevice = SampleApplication.getRxBleClient(this).getBleDevice(macAddress);
        connectionObservable = prepareConnectionObservable();
        //noinspection ConstantConditions
        getSupportActionBar().setSubtitle(getString(R.string.mac_address, macAddress));
        
        intData();
    }

    private void intData() {
        byte[] open = DataTools.getInstance().sendWPh(DataTools.OPEN, 13532385018L);
        byte[] openAuto = DataTools.getInstance().sendWPh(DataTools.OPEN_AUTO, 13532385018L);
        byte[] lock = DataTools.getInstance().sendWPh(DataTools.LOCK, 13532385018L);
        byte[] alarmEn=DataTools.getInstance().sendWPh(DataTools.ALARM_ENTER,13532385018L);
        byte[] alarmEx=DataTools.getInstance().sendWPh(DataTools.ALARM_EXIT,13532385018L);
        opearteData = new byte[][]{open, openAuto, lock,alarmEn,alarmEx};
    }

    private Observable<RxBleConnection> prepareConnectionObservable() {
        return bleDevice
                .establishConnection(false)
                .takeUntil(disconnectTriggerSubject)
                .compose(bindUntilEvent(PAUSE))
                .compose(new ConnectionSharingAdapter());
    }

    @OnClick(R.id.connect)
    public void onConnectToggleClick() {

        if (isConnected()) {
            triggerDisconnect();
        } else {
            connectionObservable
                    .flatMap(RxBleConnection::discoverServices)
                    .flatMap(rxBleDeviceServices -> rxBleDeviceServices.getCharacteristic(uuidNotify))
                    .observeOn(AndroidSchedulers.mainThread())
                    .doOnSubscribe(() -> connectButton.setText(R.string.connecting))
                    .subscribe(
                            characteristic -> {
                                updateUI(characteristic);
                                Log.i(getClass().getSimpleName(), "Hey, connection has been established!");
                            },
                            this::onConnectionFailure,
                            this::onConnectionFinished
                    );


        }
    }

    @OnClick(R.id.read)
    public void onReadClick() {

        if (isConnected()) {
            connectionObservable
                    .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(r1))
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(bytes -> {
                        readOutputView.setText(new String(bytes));
                        readHexOutputView.setText(HexString.bytesToHex(bytes));
                        writeInput.setText(HexString.bytesToHex(bytes));
                    }, this::onReadFailure);
        }
    }

    @OnClick(R.id.write)
    public void onWriteClick() {
//
        if (isConnected()) {
            senData(getInputBytes());
        }



    }

    @OnClick(R.id.spinner)
    public void onWriteTeClick() {
//
        if (isConnected()) {
            showClassPopupWindow();
        }



    }

    private void senData(byte[] send) {
        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.writeCharacteristic(uuidSend, send))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        bytes -> onWriteSuccess(),
                        this::onWriteFailure
                );
    }

    private PopupWindow mPopWindow;
    private void showClassPopupWindow() {
        View contentView = LayoutInflater.from(MultCharActivity.this).inflate(R.layout.xlb_leababy_select, null);
        mPopWindow = new PopupWindow(contentView,
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        ListView listView = (ListView) contentView.findViewById(R.id.lv_babySelect);


        String []data ={"open","openAuto","lock","alarmEn","alarmEx"};

        ArrayAdapter<String> array=new ArrayAdapter<>(this,
                android.R.layout.simple_list_item_1,data);
        listView.setAdapter(array);
        listView.setOnItemClickListener((parent, view, position, id) -> {

            senData(opearteData[position]);
            mPopWindow.dismiss();
        });
//        mPopWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
//            @Override
//            public void onDismiss() {
//
//            }
//        });

        mPopWindow.showAsDropDown(spinner);
    }
    @OnClick(R.id.notify)
    public void onNotifyClick() {

        if (isConnected()) {
            connectionObservable

                    .flatMap(rxBleConnection -> rxBleConnection.setupNotification(uuidNotify))
                    .doOnNext(notificationObservable -> runOnUiThread(this::notificationHasBeenSetUp))
                    .flatMap(notificationObservable -> notificationObservable)
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(this::onNotificationReceived, this::onNotificationSetupFailure);
        }
//
//        // Handle an error here.
//        Subscription subscribe = connectionObservable
//                .flatMap(rxBleConnection -> rxBleConnection.setupNotification(test)
//                        .doOnNext(notificationObservable -> runOnUiThread(this::notificationHasBeenSetUp))
//                        .flatMap(bytes -> rxBleConnection.writeCharacteristic(test, getInputBytes()))
//                )
//                .subscribe(
//                        writeBytes -> {
//                            // Written data.
//                            onWriteSuccess();
//                        },
//                        this::onWriteFailure
//                );
    }

    private boolean isConnected() {
        return bleDevice.getConnectionState() == RxBleConnection.RxBleConnectionState.CONNECTED;
    }

    private void onConnectionFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Connection error: " + throwable, Snackbar.LENGTH_SHORT).show();
        updateUI(null);
    }

    private void onConnectionFinished() {
        updateUI(null);
    }

    private void onReadFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Read error: " + throwable, Snackbar.LENGTH_SHORT).show();
    }

    private void onWriteSuccess() {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Write success", Snackbar.LENGTH_SHORT).show();
    }

    private void onWriteFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Write error: " + throwable, Snackbar.LENGTH_SHORT).show();
    }

    private void onNotificationReceived(byte[] bytes) {
        //noinspection ConstantConditions
        readButton.setEnabled(true);
        writeButton.setEnabled(true);
        notifyButton.setEnabled(true);
        Log.v("uuidNotify",HexString.bytesToHex(bytes));
        Snackbar.make(findViewById(R.id.main), "Change: " + HexString.bytesToHex(bytes), Snackbar.LENGTH_SHORT).show();
    }

    private void onNotificationSetupFailure(Throwable throwable) {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Notifications error: " + throwable, Snackbar.LENGTH_SHORT).show();
    }

    private void notificationHasBeenSetUp() {
        //noinspection ConstantConditions
        Snackbar.make(findViewById(R.id.main), "Notifications has been set up", Snackbar.LENGTH_SHORT).show();
    }

    private void triggerDisconnect() {
        disconnectTriggerSubject.onNext(null);

    }


    /**
     * This method updates the UI to a proper state.
     *
     * @param characteristic a nullable {@link BluetoothGattCharacteristic}. If it is null then UI is assuming a disconnected state.
     */
    private void updateUI(BluetoothGattCharacteristic characteristic) {
        connectButton.setText(characteristic != null ? R.string.disconnect : R.string.connect);
        readButton.setEnabled(true);
        writeButton.setEnabled(true);
        notifyButton.setEnabled(true);
    }

    private boolean hasProperty(BluetoothGattCharacteristic characteristic, int property) {
        return characteristic != null && (characteristic.getProperties() & property) > 0;
    }

    private byte[] getInputBytes() {

        int[] bytes=new int[13 + 4];
        bytes[0]=0xcc;
        bytes[1]=0x5e;
        bytes[2]=0xfa;
        bytes[3]=0xce;
        bytes[4]=0x97;
        bytes[5]=0x26;
        bytes[6]=0x3;
        bytes[7]=0xa1;
        bytes[8]=0xfa;
        bytes[9]=0xce;
        bytes[10]=0x97;
        bytes[11]=0x26;
        bytes[12]=0x3;
//
//        int[] ger= DataTools.getInstance().encode(bytes);
//        byte[] bbb= new byte[19];
//        bbb[0]=(byte)0x55;
//        bbb[1]=(byte)0x11;
//        for (int i = 0 ; i < 13 + 4;i++){
//            System.out.println(ger[i]);
//            bbb[i+2]=(byte)ger[i];
//        }
//        System.out.println("DATA"+HexString.bytesToHex(bbb));
//        return HexString.hexToBytes(writeInput.getText().toString());

//        byte[] send=DataTools.getInstance().sendOne(DataTools.LOCK_STATUS_CHECK,13532385018L);
        byte[] send=DataTools.getInstance().sendWPh(DataTools.OPEN,13532385018L);
        System.out.println("DataToolsTest==  "+ HexString.bytesToHex(send));
        return send;
    }
}
